#ifdef KITSCHY_DEBUG_MEMORY 
#include "debug_memorymanager.h"
#endif

#ifdef WIN32
#include "windows.h"
#else
#include <sys/time.h>
#include <time.h>
#endif
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "stdarg.h"
#include "math.h"

#include "BList.h"

#include "symbol.h"
#include "sort.h"
#include "ontology.h"
#include "featureterm.h"
#include "FTKBase.h"
#include "AUfeatureterm.h"
#include "FT_refinement.h"
#include "FT_generalization.h"

#include "entropy.h"
#include "psm.h"
#include "rFOIL.h"
#include "rINDIE.h"
#include "rINDUCTION.h"


#ifndef WIN32
struct timeval init_tick_count_value;

void setupTickCount()
{
	gettimeofday(&init_tick_count_value, NULL);
}

long GetTickCount()
{
	struct timeval now;
	gettimeofday(&now, NULL);
	struct timeval diff;
	diff.tv_sec = now.tv_sec - init_tick_count_value.tv_sec;
	diff.tv_usec = now.tv_usec - init_tick_count_value.tv_usec;
	if (diff.tv_usec < 0)
	{
		diff.tv_sec--;
		diff.tv_usec+=1000000;
	}
	return diff.tv_sec*1000 + diff.tv_usec/1000;
}
#endif



int main(void)
{
	int t_start,t_end;

#ifndef WIN32
	setupTickCount();
#endif

	Ontology *o=new Ontology();
	FTKBase *case_base=new FTKBase(o);
	FTKBase *domain_model=new FTKBase(o);

	domain_model->create_boolean_objects(o);
	case_base->uses(domain_model);

	printf("Stats 0: %i %i\n",Symbol::stats_nSymbols(),Symbol::stats_nSymbolReferences());

	{


//		domain_model->ImportNOOS("../NOOS/melanomes-Ontology.noos",o);
//		case_base->ImportNOOS("../NOOS/melanomes-CB-77.noos",o);
//		case_base->ImportNOOS("../NOOS/melanomes-CB-derma-77.noos",o);
//		case_base->ImportNOOS("../NOOS/melanomes-CB-histo-77.noos",o);

/*
		domain_model->ImportNOOS("../NOOS/robots-ontology.noos",o);
		domain_model->ImportNOOS("../NOOS/robots-dm.noos",o);
		case_base->ImportNOOS("../NOOS/robots-cases-6.noos",o);
*/

/*
		domain_model->ImportNOOS("../NOOS/trains-ontology.noos",o);
		domain_model->ImportNOOS("../NOOS/trains-dm.noos",o);
		case_base->ImportNOOS("../NOOS/trains-cases-10.noos",o);
*/

/*
		domain_model->ImportNOOS("../NOOS/family-ontology.noos",o);
		domain_model->ImportNOOS("../NOOS/family-dm.noos",o);
		case_base->ImportNOOS("../NOOS/family-cases-12.noos",o);
//		case_base->ImportNOOS("../NOOS/family-cases-12-sets.noos",o);
*/

/*
		domain_model->ImportNOOS("../NOOS/zoology-ontology.noos",o);
		domain_model->ImportNOOS("../NOOS/zoology-DM.noos",o);
		case_base->ImportNOOS("../NOOS/zoology-cases-101.noos",o);
*/

/*
		domain_model->ImportNOOS("../NOOS/monks-ontology.noos",o);
		domain_model->ImportNOOS("../NOOS/monks-DM.noos",o);
		case_base->ImportNOOS("../NOOS/monks-1-train.noos",o);
//		case_base->ImportNOOS("../NOOS/monks-2-train.noos",o);
//		case_base->ImportNOOS("../NOOS/monks-3-train.noos",o);
*/

/*
		domain_model->ImportNOOS("../NOOS/soybean-ontology.noos",o);
		domain_model->ImportNOOS("../NOOS/soybean-dm.noos",o);
		case_base->ImportNOOS("../NOOS/soybean-cases-307.noos",o);
*/


		domain_model->ImportNOOS("../NOOS/sponge-ontology.noos",o);
		domain_model->ImportNOOS("../NOOS/sponge-dm.noos",o);
//		case_base->ImportNOOS("../NOOS/sponge-cases-503.noos",o);
//		case_base->ImportNOOS("../NOOS/sponge-cases-280.noos",o);
		case_base->ImportNOOS("../NOOS/sponge-cases-120.noos",o);
//		case_base->ImportNOOS("../NOOS/sponge-cases-test.noos",o);


/*
//      OLD FILES: --------------------------------------------------------------------
		domain_model->ImportNOOS("../NOOS/toxicology-eva/toxicology-ontology.noos",o);
		domain_model->ImportNOOS("../NOOS/toxicology-eva/toxicology-dm.noos",o);
		case_base->ImportNOOS("../NOOS/toxicology-eva/toxicology-descriptions.noos",o);
//		case_base->ImportNOOS("../NOOS/toxicology-eva/toxicology-descriptions-50.noos",o);
		case_base->ImportNOOS("../NOOS/toxicology-eva/toxicology-problems.noos",o);
		case_base->ImportNOOS("../NOOS/toxicology-eva/toxicology-cases-502.noos",o);
//		case_base->ImportNOOS("../NOOS/toxicology-eva/toxicology-cases-50.noos",o);
*/

/*
//      NEW FILES: --------------------------------------------------------------------
		domain_model->ImportNOOS("../NOOS/toxic-eva-ontology.noos",o);
		domain_model->ImportNOOS("../NOOS/toxic-eva-dm.noos",o);
//		case_base->ImportNOOS("../NOOS/toxic-eva-cases-10.noos",o);
//		case_base->ImportNOOS("../NOOS/toxic-eva-cases-50.noos",o);
		case_base->ImportNOOS("../NOOS/toxic-eva-cases-100.noos",o);
//		case_base->ImportNOOS("../NOOS/toxic-eva-cases-371.noos",o);
*/


		printf("Stats 1: %i %i\n",Symbol::stats_nSymbols(),Symbol::stats_nSymbolReferences());

		printf("There are %i + %i undefined terms.\n",domain_model->get_n_undefined_terms(),case_base->get_n_undefined_terms());
		domain_model->print_undefined_terms();
		case_base->print_undefined_terms();

		t_start=GetTickCount();

		{
			Path *dp=new Path,*sp=new Path;

			List<FeatureTerm> *cases;

			dp->Add(new Symbol("description"));
//			sp->Add(new Symbol("diagnosis"));
//			sp->Add(new Symbol("elm-diagnosis"));
			sp->Add(new Symbol("solution"));
			sp->Add(new Symbol("order"));
//			sp->Add(new Symbol("m-rats"));

//			cases=case_base->SearchFT(o->get_sort("melanoma-problem"));
//			cases=case_base->SearchFT(o->get_sort("robot-problem"));
//			cases=case_base->SearchFT(o->get_sort("monks-problem"));
//			cases=case_base->SearchFT(o->get_sort("trains-problem"));
//			cases=case_base->SearchFT(o->get_sort("zoo-problem"));
			cases=case_base->SearchFT(o->get_sort("sponge-problem"));
//			cases=case_base->SearchFT(o->get_sort("soybean-problem"));
//			cases=case_base->SearchFT(o->get_sort("uncle-problem"));
//			cases=case_base->SearchFT(o->get_sort("toxic-problem"));

			// There is some problem with either antiunification or subsumption. This is just debugging code:
			// OK, the problem is not subsum[ption, I'm sure some refinement is not being generated...
/*
			{
				char *g1 = 
			"(define (sponge) "
			"  (external-features (define (external-features) "
			"                       (growing (define (growing) "
			"                                  (line-form (define (line-form))))))) "
			"  (ecological-features (define (ecological-features) "
			"                         (location mediterranean))) "
			"  (spiculate-skeleton (define (spiculate-skeleton) "
			"                        (megascleres (define (megascleres) "
			"                                       (smooth-form "
//			"												(define (set) "
			"                                                      style "
//			"                                                      (define (megas-form)) "
//			" ) "
			" ))) "
			"                        (uniform-length (define (new-boolean)))))) ";
				char *g2 = 
			"(define (sponge) "
			"  (external-features (define (external-features) "
			"                       (growing (define (growing) "
			"                                  (line-form (define (line-form))))))) "
			"  (ecological-features (define (ecological-features) "
			"                         (location mediterranean))) "
			"  (spiculate-skeleton (define (spiculate-skeleton) "
			"                        (megascleres (define (megascleres) "
			"                                       (smooth-form "
			"												(define (set) "
			"                                                      style "
			"                                                      (define (megas-form)) "
			" ) "
			" ))) "
			"                        (uniform-length (define (new-boolean)))))) ";

				FeatureTerm *f1 = FeatureTerm::fromStringNOOS(g1,domain_model,o);
				FeatureTerm *f2 = FeatureTerm::fromStringNOOS(g2,domain_model,o);

				if (f1->subsumes(f2)) printf("f1 subsumes f2\n");
								 else printf("f1 does not subsume f2\n");
				if (f2->subsumes(f1)) printf("f2 subsumes f1\n");
								 else printf("f2 does not subsume f1\n");

				// This is to verify that subsumption was correct (it is):
				FeatureTerm *c,*s,*d;
				List<FeatureTerm> *l,dl;

				cases->Rewind();
				while(cases->Iterate(c)) {
					l = c->readPath(dp);
					d = l->ExtractIni();
					delete l;
					l = c->readPath(sp);
					s = l->ExtractIni();
					delete l;

					if (!f1->subsumes(d)) {
						printf("No subsume %s\n",c->getName()->get());
					} else {
						printf("subsume %s\n",c->getName()->get());
					}

					// Form the axinellida group:
					{
						char *str = s->toStringNOOS(domain_model);
						if (strcmp(str,"axinellida")==0) {
							dl.Add(d);
						} else {
							delete d;
						}
						delete s;
					}
				}

				printf("Axinellida group has %i cases\n",dl.Length());

				// This is to verify if refinement is correct:
				FeatureTerm *r;
				l=DSpecializationL2(f1,&dl,0,o,-1,domain_model);

				l->Rewind();
				while(l->Iterate(r)) {
					char *s = r->toStringNOOS(domain_model);
					printf("%s\n",s);
					delete []s;
				}


				delete f1;
				delete f2;
			}
*/

			{
//				rFOILHypothesis *h;
				rINDIEHypothesis *h;
//				rINDUCTIONHypothesis *h;
//				FeatureTerm *solution=new FeatureTerm();
//				solution->fromStringNOOS("1",domain_model,o);
//				solution->fromStringNOOS("east",domain_model,o);
//				solution->fromStringNOOS("friendly",domain_model,o);

//				h=new rFOILHypothesis();
//				h->learn(cases,dp,sp,o,domain_model,0);	// Gain  
//				h->learn_single_class(solution,cases,dp,sp,o,domain_model,0);	// Gain  
//				h->learn2(cases,dp,sp,o,domain_model,0);	// Gain  
//				h->learn2_single_class(solution,cases,dp,sp,o,domain_model,0);	// Gain  
//				h->learn3(cases,dp,sp,o,domain_model,0);	// Gain  
//				h->learn3_single_class(solution,cases,dp,sp,o,domain_model,0);	// Gain  
//				delete h;

				h=new rINDIEHypothesis();
//				h->learn(cases,dp,sp,o,domain_model,0);
//				h->learn_single_class(solution,cases,dp,sp,o,domain_model,0);
//				h->learn2c(cases,dp,sp,o,domain_model,0);
//				h->learn2c_single_class(solution,cases,dp,sp,o,domain_model,0);
				h->learn2h(cases,dp,sp,o,domain_model,0);
//				h->learn2h_single_class(solution,cases,dp,sp,o,domain_model,0);
				h->show_rule_set(domain_model);
				delete h;

//				h=new rINDUCTIONHypothesis();
//				h->learn(cases,dp,sp,o,domain_model);
//				h->learn_single_class(solution,cases,dp,sp,o,domain_model);
//				h->learn2(cases,dp,sp,o,domain_model);
//				h->learn2_single_class(solution,cases,dp,sp,o,domain_model);
//				h->learn3(cases,dp,sp,o,domain_model);
//				h->learn3_single_class(solution,cases,dp,sp,o,domain_model);
//				h->show_rule_set(domain_model);
//				delete h;
				
//				delete solution;
			} 

/*
				{
					List<FeatureTerm> l,*l2;
					FeatureTerm *problem,*description,*solution;
					float score = 0;
					int problems = 0;

					l.Instance(*cases);
					l.Rewind();
					while(l.Iterate(problem)) {
						List<FeatureTerm> training_set;
						training_set.AddAll(cases);
						training_set.DeleteElement(problem);

						l2 = problem->readPath(dp);
						description = l2->ExtractIni();
						delete l2;
						l2 = problem->readPath(sp);
						solution = l2->ExtractIni();
						delete l2;
						
						Prediction *p = eva_LID(description, &training_set, dp, sp, o, domain_model,0,0, 1);

						training_set.ExtractAll();
						
						if (p!=0) {
							p->print(domain_model);
						} else {
							printf("No prediction found.");
						}
						
						score+=p->getScore(solution);
						problems++;
					}
					
					printf("Final Score: %g in %i problems",((score/problems)*100),problems);
				}

*/
			while(!cases->EmptyP()) cases->ExtractIni();
			delete cases;

			delete dp;
			delete sp;

		}



		t_end=GetTickCount();

		printf("Time taken: %i\n",t_end-t_start);

		printf("Stats 2: %i %i\n",Symbol::stats_nSymbols(),Symbol::stats_nSymbolReferences());
	}

	delete case_base;
	delete domain_model;

	printf("Stats 3: %i %i\n",Symbol::stats_nSymbols(),Symbol::stats_nSymbolReferences());

	delete o;

	printf("Stats 4: %i %i\n",Symbol::stats_nSymbols(),Symbol::stats_nSymbolReferences());
	Symbol::stats_printSymbolStats();

	Symbol::reset();

	return 0;
} /* main */ 




